/*
 * Copyright (c) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { TapGestureHandler, TapGestureHandlerGestureEvent } from 'react-native-gesture-handler';
import Animated, { Extrapolation, interpolate, runOnJS, useAnimatedGestureHandler, useAnimatedReaction, useAnimatedStyle } from 'react-native-reanimated';
import { styles } from './styles';
import { AdaptiveSheetDefaultBackdropProps } from './types';
import { ViewProps } from 'react-native';
import { useAdaptiveSheet } from '../../hooks';

const DEFAULT_OPACITY = 0.64;
const DEFAULT_APPEARS_ON_INDEX = 1;
const DEFAULT_DISAPPEARS_ON_INDEX = 0;
const DEFAULT_ENABLE_TOUCH_THROUGH = false;
const DEFAULT_PRESS_BEHAVIOR = 'close' as const;

// 遮罩组件
const AdaptiveSheetBackdropComponent = ({
  animatedIndex,
  opacity: _providedOpacity,
  appearsOnIndex: _providedAppearsOnIndex,
  disappearsOnIndex: _providedDisappearsOnIndex,
  enableTouchThrough: _providedEnableTouchThrough,
  pressBehavior = DEFAULT_PRESS_BEHAVIOR,
  onPress,
  style,
  children,
  ...rest
}: AdaptiveSheetDefaultBackdropProps): JSX.Element => {
  const { snapToIndex, close } = useAdaptiveSheet();
  const isMounted = useRef(false);

  const opacity = _providedOpacity ?? DEFAULT_OPACITY;
  const appearsOnIndex = _providedAppearsOnIndex ?? DEFAULT_APPEARS_ON_INDEX;
  const disappearsOnIndex = _providedDisappearsOnIndex ?? DEFAULT_DISAPPEARS_ON_INDEX;
  const enableTouchThrough = _providedEnableTouchThrough ?? DEFAULT_ENABLE_TOUCH_THROUGH;

  const [pointerEvents, setPointerEvents] = useState<ViewProps['pointerEvents']>(enableTouchThrough ? 'none' : 'auto');

  const handleOnPress = useCallback(() => {
    onPress?.();

    if (pressBehavior === 'close') {
      close();
    } else if (pressBehavior === 'collapse') {
      snapToIndex(disappearsOnIndex as number);
    } else if (typeof pressBehavior === 'number') {
      snapToIndex(pressBehavior);
    }
  }, [snapToIndex, close, disappearsOnIndex, pressBehavior, onPress]);
  const handleContainerTouchability = useCallback((shouldDisableTouchability: boolean) => {
    isMounted.current && setPointerEvents(shouldDisableTouchability ? 'none' : 'auto');
  }, []);

  const gestureHandler = useAnimatedGestureHandler<TapGestureHandlerGestureEvent>(
    {
      onFinish: () => {
        runOnJS(handleOnPress)();
      },
    },
    [handleOnPress],
  );

  const containerAnimatedStyle = useAnimatedStyle(() => ({
    opacity: interpolate(
      animatedIndex.value, // 当前吸附点索引
      [-1, disappearsOnIndex, appearsOnIndex],
      [0, 0, opacity],
      Extrapolation.CLAMP, // 限制插值结果在输出范围内,防止透明度超出 0-1 的有效范围
    ),
    flex: 1,
  }));
  const containerStyle = useMemo(() => [styles.container, style, containerAnimatedStyle], [style, containerAnimatedStyle]);

  useAnimatedReaction(
    () => animatedIndex.value <= disappearsOnIndex,
    (shouldDisableTouchability, previous) => {
      if (shouldDisableTouchability === previous) {
        return;
      }
      runOnJS(handleContainerTouchability)(shouldDisableTouchability);
    },
    [disappearsOnIndex],
  );

  useEffect(() => {
    isMounted.current = true;
    return () => {
      isMounted.current = false;
    };
  }, []);

  const AnimatedView = (
    <Animated.View style={containerStyle} pointerEvents={pointerEvents} {...rest}>
      {children}
    </Animated.View>
  );

  return pressBehavior !== 'none' ? <TapGestureHandler onGestureEvent={gestureHandler}>{AnimatedView}</TapGestureHandler> : AnimatedView;
};

const AdaptiveSheetBackdrop = memo(AdaptiveSheetBackdropComponent);
AdaptiveSheetBackdrop.displayName = 'AdaptiveSheetBackdrop';

export default AdaptiveSheetBackdrop;
